{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import rope.base.project\n",
    "from rope.refactor.extract import ExtractMethod\n",
    "import re"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "71 81\n",
      "--- a/class_refactor.py\n",
      "+++ b/class_refactor.py\n",
      "@@ -1,4 +1,8 @@\n",
      " class Foo:\n",
      "     def __init__(self):\n",
      "         self.a = 1\n",
      "-        self.b = 2 * self.a\n",
      "+        self.b = Foo.helper(self)\n",
      "+\n",
      "+    @classmethod\n",
      "+    def helper(cls, self):\n",
      "+        return 2 * self.a\n",
      "\n"
     ]
    }
   ],
   "source": [
    "\n",
    "APOSTROPHE_MARKER = \"__APOSTROPHE__\"\n",
    "\n",
    "def serialize(text: str):\n",
    "    # Replace \"'{var}'\" with \"__APOSTROPHE__{var}__APOSTROPHE__\"\n",
    "    return re.sub(r\"'{(.*?)}'\", f\"{APOSTROPHE_MARKER}{{\\\\1}}{APOSTROPHE_MARKER}\", text)\n",
    "\n",
    "\n",
    "def deserialize(text: str):\n",
    "    return re.sub(f\"{APOSTROPHE_MARKER}{{(.*?)}}{APOSTROPHE_MARKER}\", \"'{\\\\1}'\", text)\n",
    "\n",
    "\n",
    "myproject = rope.base.project.Project('src')\n",
    "\n",
    "myresource = myproject.get_resource('class_refactor.py')\n",
    "contents = myresource.read()\n",
    "serialized_contents = serialize(myresource.read())\n",
    "myresource.write(serialized_contents)\n",
    "extract_span = r'''2 * self.a'''\n",
    "serialized_extract_span = serialize(extract_span)\n",
    "\n",
    "start, end = serialized_contents.find(serialized_extract_span), serialized_contents.find(serialized_extract_span) + len(serialized_extract_span)\n",
    "print(start, end)\n",
    "\n",
    "try:\n",
    "    extractor = ExtractMethod(myproject, myresource, start, end)\n",
    "    change_set = extractor.get_changes(\"@helper\")\n",
    "    for change in change_set.changes:\n",
    "        if change.old_contents is not None:\n",
    "            change.old_contents = deserialize(change.old_contents)\n",
    "        else:\n",
    "            change.old_contents = deserialize(change.resource.read())\n",
    "        change.new_contents = deserialize(change.new_contents)\n",
    "    for change in change_set.changes:\n",
    "        print(change.get_description())\n",
    "except Exception as e:\n",
    "    print(e)\n",
    "finally:\n",
    "    myresource.write(contents)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "f-string: invalid syntax (<string>, line 5)",
     "output_type": "error",
     "traceback": [
      "Traceback \u001b[0;36m(most recent call last)\u001b[0m:\n",
      "\u001b[0m  File \u001b[1;32m~/.cache/pypoetry/virtualenvs/sweepai-u_CIt3kb-py3.10/lib/python3.10/site-packages/IPython/core/interactiveshell.py:3526\u001b[0m in \u001b[1;35mrun_code\u001b[0m\n    exec(code_obj, self.user_global_ns, self.user_ns)\u001b[0m\n",
      "\u001b[0m  Cell \u001b[1;32mIn[37], line 32\u001b[0m\n    print(extract_method(snippet, \"handlers/on_ticket.py\", \"hydrate_sandbox\"))\u001b[0m\n",
      "\u001b[0m  Cell \u001b[1;32mIn[37], line 14\u001b[0m in \u001b[1;35mextract_method\u001b[0m\n    change_set = extractor.get_changes(method_name, similar=True, global_=True)\u001b[0m\n",
      "\u001b[0m  File \u001b[1;32m~/.cache/pypoetry/virtualenvs/sweepai-u_CIt3kb-py3.10/lib/python3.10/site-packages/rope/refactor/extract.py:82\u001b[0m in \u001b[1;35mget_changes\u001b[0m\n    new_contents = _ExtractPerformer(info).extract()\u001b[0m\n",
      "\u001b[0m  File \u001b[1;32m~/.cache/pypoetry/virtualenvs/sweepai-u_CIt3kb-py3.10/lib/python3.10/site-packages/rope/refactor/extract.py:287\u001b[0m in \u001b[1;35mextract\u001b[0m\n    extract_info = self._collect_info()\u001b[0m\n",
      "\u001b[0m  File \u001b[1;32m~/.cache/pypoetry/virtualenvs/sweepai-u_CIt3kb-py3.10/lib/python3.10/site-packages/rope/refactor/extract.py:314\u001b[0m in \u001b[1;35m_collect_info\u001b[0m\n    self._find_matches(extract_collector)\u001b[0m\n",
      "\u001b[0m  File \u001b[1;32m~/.cache/pypoetry/virtualenvs/sweepai-u_CIt3kb-py3.10/lib/python3.10/site-packages/rope/refactor/extract.py:328\u001b[0m in \u001b[1;35m_find_matches\u001b[0m\n    for region_match in region_matches:\u001b[0m\n",
      "\u001b[0m  File \u001b[1;32m~/.cache/pypoetry/virtualenvs/sweepai-u_CIt3kb-py3.10/lib/python3.10/site-packages/rope/refactor/similarfinder.py:107\u001b[0m in \u001b[1;35mget_matches\u001b[0m\n    for match in self._get_matched_asts(code):\u001b[0m\n",
      "\u001b[0m  File \u001b[1;32m~/.cache/pypoetry/virtualenvs/sweepai-u_CIt3kb-py3.10/lib/python3.10/site-packages/rope/refactor/similarfinder.py:116\u001b[0m in \u001b[1;35m_get_matched_asts\u001b[0m\n    wanted = self._create_pattern(code)\u001b[0m\n",
      "\u001b[0m  File \u001b[1;32m~/.cache/pypoetry/virtualenvs/sweepai-u_CIt3kb-py3.10/lib/python3.10/site-packages/rope/refactor/similarfinder.py:123\u001b[0m in \u001b[1;35m_create_pattern\u001b[0m\n    node = ast.parse(expression)\u001b[0m\n",
      "\u001b[0m  File \u001b[1;32m~/.cache/pypoetry/virtualenvs/sweepai-u_CIt3kb-py3.10/lib/python3.10/site-packages/rope/base/ast.py:33\u001b[0m in \u001b[1;35mparse\u001b[0m\n    return ast.parse(source, filename=filename, *args, **kwargs)\u001b[0m\n",
      "\u001b[0;36m  File \u001b[0;32m/usr/lib/python3.10/ast.py:50\u001b[0;36m in \u001b[0;35mparse\u001b[0;36m\n\u001b[0;31m    return compile(source, filename, mode, flags,\u001b[0;36m\n",
      "\u001b[0;36m  File \u001b[0;32m<string>:5\u001b[0;36m\u001b[0m\n\u001b[0;31m    (${pr}.html_url)\u001b[0m\n\u001b[0m     ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m f-string: invalid syntax\n"
     ]
    }
   ],
   "source": [
    "def extract_method(\n",
    "    snippet,\n",
    "    file_path,\n",
    "    method_name,\n",
    "    project_name=\"../../sweepai\"\n",
    "):\n",
    "    project = rope.base.project.Project(project_name)\n",
    "\n",
    "    resource = project.get_resource(file_path)\n",
    "    contents = resource.read()\n",
    "    start, end = contents.find(snippet), contents.find(snippet) + len(snippet)\n",
    "\n",
    "    extractor = ExtractMethod(project, resource, start, end)\n",
    "    change_set = extractor.get_changes(method_name, similar=True, global_=True)\n",
    "    for change in change_set.changes:\n",
    "        change.do()\n",
    "\n",
    "    result = resource.read()\n",
    "\n",
    "    for change in change_set.changes:\n",
    "        change.undo()\n",
    "    return result\n",
    "\n",
    "snippet = r\"\"\"edit_sweep_comment(\n",
    "                review_message + \"\\n\\nSuccess! 🚀\",\n",
    "                4,\n",
    "                pr_message=(\n",
    "                    f\"## Here's the PR! [{pr.html_url}]({pr.html_url}).\\n{center(payment_message_start)}\"\n",
    "                ),\n",
    "                done=True,\n",
    "            )\"\"\"\n",
    "print(extract_method(snippet, \"handlers/on_ticket.py\", \"hydrate_sandbox\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.10.10 ('sweepai-u_CIt3kb-py3.10')",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.10"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "25d341f3248a096a89b9dbf6eec8e41f63aed02f6ba059df22a49224e3e8f1b0"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
